package com.dkd.manage.service.impl;

import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.dkd.common.constant.DkdContants;
import com.dkd.common.exception.ServiceException;
import com.dkd.common.utils.DateUtils;
import com.dkd.manage.domain.Emp;
import com.dkd.manage.domain.TaskDetails;
import com.dkd.manage.domain.VendingMachine;
import com.dkd.manage.domain.dto.TaskDTO;
import com.dkd.manage.domain.dto.TaskDetailDTO;
import com.dkd.manage.domain.vo.TaskVO;
import com.dkd.manage.mapper.EmpMapper;
import com.dkd.manage.mapper.TaskDetailsMapper;
import com.dkd.manage.mapper.VendingMachineMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.dkd.manage.mapper.TaskMapper;
import com.dkd.manage.domain.Task;
import com.dkd.manage.service.ITaskService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 工单Service业务层处理
 *
 * @author 久睡成瘾
 * @date 2025-10-20
 */
@Service
public class TaskServiceImpl implements ITaskService {
    @Autowired
    private TaskMapper taskMapper;
    @Autowired
    private VendingMachineMapper vendingMachineMapper;
    @Autowired
    private EmpMapper empMapper;
    @Autowired
    private TaskDetailsMapper taskDetailsMapper;
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    /**
     * 查询工单
     *
     * @param taskId 工单主键
     * @return 工单
     */
    @Override
    public Task selectTaskByTaskId(Long taskId) {
        return taskMapper.selectTaskByTaskId(taskId);
    }

    /**
     * 查询工单列表
     *
     * @param task 工单
     * @return 工单
     */
    @Override
    public List<Task> selectTaskList(Task task) {
        return taskMapper.selectTaskList(task);
    }


    /**
     * 查询工单VO列表
     *
     * @param task 工单
     * @return 工单
     */
    @Override
    public List<TaskVO> selectTaskVOList(Task task) {
        return taskMapper.selectTaskVOList(task);
    }
//    /**
//     * 新增工单
//     *
//     * @param task 工单
//     * @return 结果
//     */
//    @Override
//    public int insertTask(Task task)
//    {
//        task.setCreateTime(DateUtils.getNowDate());
//        return taskMapper.insertTask(task);
//    }

    /**
     * 新增工单
     *
     * @param taskDto 工单
     * @return 结果
     */
    @Override
    @Transactional
    public int insertTask(TaskDTO taskDto) {
        Date nowDate = DateUtils.getNowDate();
        Long productTypeId = taskDto.getProductTypeId();
        //根据设备编号查询设备
        VendingMachine vm = vendingMachineMapper.selectVendingMachineByInnerCode(taskDto.getInnerCode());
        //1、校验设备是否存在
        if (vm == null) {
            throw new ServiceException("设备不存在");
        }
        String innerCode = vm.getInnerCode();
        //根据执行人id查询员工
        Emp emp = empMapper.selectEmpById(taskDto.getUserId());
        //2、校验执行人是否存在
        if (emp == null) {
            throw new ServiceException("执行人不存在");
        }
        //校验员工区域是否匹配
        if (!vm.getRegionId().equals(emp.getRegionId())) {
            //区域不匹配
            throw new ServiceException("执行人与设备不在同一区域");
        }
        //3、根据工单类型和设备状态校验逻辑上是否匹配
        checkTaskStatus(productTypeId, vm.getVmStatus());
        //4、校验该设备是否存在同类型工单
        hasEqualTask(innerCode, productTypeId);

        //工单dto转po插入
        //补充po字段
        Task task = new Task();
        BeanUtils.copyProperties(taskDto,task);
        //设置工单编号
        task.setTaskCode(genTaskCode());
        //设置初始工单状态
        task.setTaskStatus(DkdContants.TASK_STATUS_CREATE);
        //设置执行人（员工）冗余字段信息
        task.setUserName(emp.getUserName());
        task.setRegionId(vm.getRegionId());
        //设置地址
        task.setAddr(vm.getAddr());
        //设置创建时间更新时间
        task.setCreateTime(nowDate);
        task.setUpdateTime(nowDate);
        //插入工单信息并拿到返回主键
        int result = taskMapper.insertTask(task);


        //判断是否为补货工单
        if (productTypeId.equals(DkdContants.TASK_TYPE_SUPPLY)) {
            //将补货信息dto转为po再批量插入
            List<TaskDetailDTO> detailDTOList = taskDto.getDetails();
            if (detailDTOList.isEmpty()){
                throw new ServiceException("补货信息不存在");
            }
            List<TaskDetails> taskDetailsList = detailDTOList.stream().map(detailDTO -> {
                TaskDetails details = new TaskDetails();
                BeanUtils.copyProperties(detailDTO, details);
                details.setTaskId(task.getTaskId());
                //设置创建时间更新时间
                details.setCreateTime(nowDate);
                details.setUpdateTime(nowDate);

                return details;
            }).collect(Collectors.toList());
            taskDetailsMapper.insertTaskDetailsBatch(taskDetailsList);

        }

        return result;
    }

    /**
     * 生成并获取当天任务代码的唯一标识。
     * 该方法首先尝试从Redis中获取当天的任务代码计数，如果不存在，则初始化为1并返回"日期0001"格式的字符串。
     * 如果存在，则对计数加1并返回更新后的任务代码。
     *
     * @return 返回当天任务代码的唯一标识，格式为"日期XXXX"，其中XXXX是四位数字的计数。
     */
    private String genTaskCode() {
        Date nowDate = DateUtils.getNowDate();
        String dateStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, nowDate).replace("-", "");
        String key = DkdContants.TASK_INDEX_PRE + dateStr;
        //向缓存中插入生成任务数量
        if (!redisTemplate.hasKey(key)){
            //缓存中不存在，设置初始值并插入缓存
            redisTemplate.opsForValue().set(key,1, Duration.ofDays(1L));

            return dateStr + "0001";
        }
        //缓存中存在key
        String value = redisTemplate.opsForValue().increment(key).toString();

        return dateStr + StrUtil.padPre(value,4,'0');
    }
    /**
     * 校验该设备是否存在同类型工单
     *
     * @param innerCode     设备编号
     * @param productTypeId 工单类型
     */
    private void hasEqualTask(String innerCode, Long productTypeId) {
        List<Task> taskList = taskMapper.selectTaskListByTaskInnerCode(innerCode);
        if (taskList == null || taskList.isEmpty()) {
            return; // 没有工单，无需校验
        }

        //集合中有一个task符合条件就返回true
        boolean exists = taskList.stream().anyMatch(task ->
                DkdContants.TASK_STATUS_PROGRESS.equals(task.getTaskStatus())
                        && productTypeId.equals(task.getProductTypeId())
        );

        if (exists) {
            throw new ServiceException("同类型工单正在进行，不可重复创建");
        }
    }

    /**
     * 根据工单类型和设备状态校验逻辑上是否匹配
     *
     * @param productTypeId 工单类型
     * @param vmStatus      设备状态
     */
    private void checkTaskStatus(Long productTypeId, Long vmStatus) {
        //为投放工单，设备不能为运营状态
        if (productTypeId.equals(DkdContants.TASK_TYPE_DEPLOY) && vmStatus.equals(DkdContants.VM_STATUS_RUNNING)) {
            throw new ServiceException("设备已运营，不可投放");
        }
        //为补货工单，设备状态必须为运营
        if (productTypeId.equals(DkdContants.TASK_TYPE_SUPPLY) && !vmStatus.equals(DkdContants.VM_STATUS_RUNNING)) {
            throw new ServiceException("设备未运营，不可补货");
        }
        //为维修工单，设备必须运营状态
        if (productTypeId.equals(DkdContants.TASK_TYPE_REPAIR) && !vmStatus.equals(DkdContants.VM_STATUS_RUNNING)) {
            throw new ServiceException("设备未运营，不可维修");
        }
        //为撤机工单，设备必须为运营状态
        if (productTypeId.equals(DkdContants.TASK_TYPE_REVOKE) && !vmStatus.equals(DkdContants.VM_STATUS_RUNNING)) {
            throw new ServiceException("设备未运营，不可撤机");
        }
    }

    /**
     * 修改工单
     *
     * @param task 工单
     * @return 结果
     */
    @Override
    public int updateTask(Task task) {
        task.setUpdateTime(DateUtils.getNowDate());
        return taskMapper.updateTask(task);
    }

    /**
     * 批量删除工单
     *
     * @param taskIds 需要删除的工单主键
     * @return 结果
     */
    @Override
    public int deleteTaskByTaskIds(Long[] taskIds) {
        return taskMapper.deleteTaskByTaskIds(taskIds);
    }

    /**
     * 删除工单信息
     *
     * @param taskId 工单主键
     * @return 结果
     */
    @Override
    public int deleteTaskByTaskId(Long taskId) {
        return taskMapper.deleteTaskByTaskId(taskId);
    }

    /**
     * 取消工单
     *
     * @param task 包含工单id和取消原因
     * @return 结果
     */
    @Override
    public int cancelTask(Task task) {
        //1、查询工单信息
        Task oldTask = taskMapper.selectTaskByTaskId(task.getTaskId());
        //2、校验工单状态是否可以取消
        Long status = oldTask.getTaskStatus();
        if (status.equals(DkdContants.TASK_STATUS_CANCEL)){
            //工单状态为取消则不可重复取消
            throw new ServiceException("工单已取消，不可重复取消");
        }
        if (status.equals(DkdContants.TASK_STATUS_FINISH)){
            //工单已完成不可取消
            throw new ServiceException("工单已完成，不可取消");
        }

        //3、设置工单状态，更新时间
        task.setTaskStatus(DkdContants.TASK_STATUS_CANCEL);
        task.setUpdateTime(DateUtils.getNowDate());
        //4、更新工单
        return taskMapper.updateTask(task);
    }


}
